const arrayEach = (list, iterate, context) => {
    if (list) {
        if (list.forEach) {
            list.forEach(iterate, context);
        } else {
            for (var index = 0, len = list.length; index < len; index++) {
                iterate.call(context, list[index], index, list);
            }
        }
    }
};

const hasOwnProp = (obj, key) => {
    // eslint-disable-next-line no-prototype-builtins
    return obj && obj.hasOwnProperty ? obj.hasOwnProperty(key) : false;
};

const objectEach = (obj, iterate, context) => {
    if (obj) {
        for (var key in obj) {
            if (hasOwnProp(obj, key)) {
                iterate.call(context, obj[key], key, obj);
            }
        }
    }
};

const each = (obj, iterate, context) => {
    if (obj) {
        return (Array.isArray(obj) ? arrayEach : objectEach)(obj, iterate, context);
    }
    return obj;
};

const eachTreeItem = (
    parent,
    obj,
    iterate,
    context,
    path,
    node,
    parseChildren,
    opts
) => {
    var paths, nodes;
    each(obj, (item, index) => {
        paths = path.concat(["" + index]);
        nodes = node.concat([item]);
        iterate.call(context, item, index, obj, paths, parent, nodes);
        if (item && parseChildren) {
            paths.push(parseChildren);
            eachTreeItem(
                item,
                item[parseChildren],
                iterate,
                context,
                paths,
                nodes,
                parseChildren,
                opts
            );
        }
    });
};

const eachArray = (list, obj, optChildren) => {
    if (!obj) {
        return;
    }
    obj.forEach((item) => {
        list.push(item);
        if (item[optChildren]) {
            eachArray(list, item[optChildren], optChildren);
        }
    });
};

/**
 * 从树结构中遍历数据的键、值、路径
 *
 * @param {Object} obj 对象/数组
 * @param {Function} iterate (item, index, items, path, parent, nodes) 回调
 * @param {Object} options {children: 'children'}
 * @param {Object} context 上下文
 */
const eachTree = (obj, iterate, options, context) => {
    if (!obj) {
        return;
    }
    var opts = options || {};
    var optChildren = options.children || "children";
    return eachTreeItem(null, obj, iterate, context, [], [], optChildren, opts);
};

/**
 * 树结构转成数组列表
 *
 * @param {Object} obj 树
 * @param {Object} options  {children: 'children'}
 * @returns Array
 */
const toTreeArray = (obj, options) => {
    var optChildren = options.children || "children";
    var list = [];
    eachArray(list, obj, optChildren);
    return list;
};

/**
 * 集合转成树形结构
 * 
 * @param {Array} arr 
 * @param {string} id 
 * @param {string} pid 
 * @param {string} children 
 * @returns 
 */
const toArrayTree = (arr, id, pid, children) => {
    var map = new Map();
    var list = [];
    arr.forEach((e) => {
        map.set(e[id], e);
    });
    arr.forEach((e) => {
        if (!e[pid] || !map.has(e[pid])) {
            list.push(e);
        } else {
            let parent = map.get(e[pid]);
            if (!parent[children]) {
                parent[children] = [];
            }
            parent[children].push(e);
        }
    });
    return list;
};

/**
  * 从树结构中根据回调过滤数据
  *
  * @param {Object} obj 对象/数组
  * @param {Function} iterate(item, index, items, path, parent) 回调
  * @param {Object} options {children: 'children'}
  * @param {Object} context 上下文
  * @return {Array}
  */
const filterTree = (arr, iterate, options, context) => {
    var result = []
    if (arr && iterate) {
        eachTree(arr, function (item, index, items, path, parent, nodes) {
            if (iterate.call(context, item, index, items, path, parent, nodes)) {
                result.push(item)
            }
        }, options)
    }
    return result
}

export default {
    eachTree,
    toTreeArray,
    toArrayTree,
    filterTree
};
